/*!
 * \file thrift_comm.c
 *
 * \brief thrift 协议解析共通部分
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 * 共通使用的宏和结构体
 *
 * \version 1.0
 * \author geyh
 * \date 2017/02/15
 *
 */
#include <conntrack.h>
#include <module.h>
#include <frct_comm.h>
#include <frlog.h>
#include <frreport_comm.h>
#include <sys/time.h>
#include "thrift_comm.h"
#include "../tcompact/tcompact.h"

/*!
 * \brief   thrift_data 链表销毁
 *
 * \arg     node    thrift_data 链表节点
 *
 * \return  void
 *
 */
void frthritf_list_node_free(Frlist_node *node)
{
    thrift_data *p_st_thrift_data = NULL;

    if(node && node->data)
    {
        p_st_thrift_data = (thrift_data *)node->data;

        if(p_st_thrift_data->p_report_comm)
            frreport_body_l7list_free(&p_st_thrift_data->p_report_comm);

        if(p_st_thrift_data->p_report_req)
            frreport_body_l7list_free(&p_st_thrift_data->p_report_req);

        frfree(p_st_thrift_data);
    }

    return;
}

/*!
 * \brief   thrift tcopact 协议 request解析
 *
 * \arg     p_st_packet         数据包
 *          p_st_private        私有数据
 *          p_st_conn           CT
 *          p_st_hash_report    上报数据链表
 *
 * \return  APM_L7_ANALYZE_FAIL 失败
 *          APM_L7_ANALYZE_SUCC 成功
 *          APM_L7_ANALYZE_TODO 数据包不完整
 *
 */
int thrift_compact_req_analyze(Apm_packet *p_st_packet, L7session_thrift_private *p_st_private
        , Conntrack *p_st_conn, Frhash_header *p_st_hash_report)
{
    Frbyte_Packet *p_packet = NULL;
    L4_transaction *p_st_l4_trans = &p_st_private->st_l4_trans;
    unsigned long ul_seq = 0, ul_tmp = 0;
    Frreport_body_data *p_st_body_data = NULL;
    Frreport_data *p_st_report_data = NULL;
    FRTcompact st_compact = {0,0,0};
    thrift_data *p_st_thrift_data = NULL;
    Frlist_node *p_st_node = NULL;

    if(p_st_private->p_st_data == NULL)
    {
        p_st_private->p_st_data = bytebuff_creat();
        if(p_st_private->p_st_data == NULL)
        {
            FRLOG_ERROR_DETAIL("malloc fail");
            return APM_L7_ANALYZE_FAIL;
        }
    }

    p_packet = p_st_private->p_st_data;
    bytebuff_add(p_packet, p_st_packet->p_payload, p_st_packet->ui_payload_len);
    p_st_l4_trans->l_request_bytes += p_st_packet->ui_payload_len;

    //第一个数据包
    if(p_st_private->ui_data_len == 0)
    {
        p_st_l4_trans->st_request_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_request_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;
        bytebuff_get_int(p_packet, 4, &p_st_private->ui_data_len, BYTE_BIG_ENDIAN);
    }


    if(p_st_private->ui_data_len > (unsigned int)bytebuff_remaining(p_packet))
        return APM_L7_ANALYZE_TODO;

    p_st_body_data = frreport_body_new_l7(p_st_conn);
    if(p_st_body_data == NULL)
    {
        FRLOG_ERROR_DETAIL("malloc fail");
        return APM_L7_ANALYZE_FAIL;
    }

    if(frthrift_tcompact_read_request(p_packet, p_st_body_data, &st_compact, (char *)"request.rpc") == FR_FAIL)
        goto ERROR;

    ul_seq = frct_seq_increase(p_st_conn);
    if(frreport_body_l7_add_ulong(p_st_body_data, APM_REPORT_KEY_REQ_ID, ul_seq) == FR_FAIL)
        goto ERROR;

    if(frreport_body_l7_add_timeval(p_st_body_data, APM_REPORT_KEY_REQ_START_TIMESTAMP, &p_st_l4_trans->st_request_time_first_byte) == FR_FAIL)
        goto ERROR;

    //one way
    if(st_compact.u8_type == 4)
    {
        if(frreport_body_l7_add_int(p_st_body_data, APM_REPORT_KEY_REQ_ISRESPREQUIRED, 0) == FR_FAIL)
            goto ERROR;
    }
    else
    {
        if(frreport_body_l7_add_int(p_st_body_data, APM_REPORT_KEY_REQ_ISRESPREQUIRED, 1) == FR_FAIL)
            goto ERROR;
    }

    //request 结束时间
    p_st_l4_trans->st_request_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_request_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

    //request_time_us
    ul_tmp = (unsigned long)frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &p_st_packet->st_timestamp);
    if(frreport_body_l7_add_ulong(p_st_body_data, APM_REPORT_KEY_REQ_SEND_TIME_US, ul_tmp) == FR_FAIL)
        goto ERROR;

    //响应字节数
    if(frreport_body_l7_add_long(p_st_body_data, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_l4_trans->l_request_bytes) == FR_FAIL)
        goto ERROR;

    if(frreport_body_l7_add_timeval(p_st_body_data, APM_REPORT_KEY_REQ_END_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
        goto ERROR;

    if(st_compact.u8_type != 4)
    {
        //request 数据保存
        p_st_thrift_data = (thrift_data *)frmalloc(sizeof(thrift_data));
        memset(p_st_thrift_data, 0x00, sizeof(thrift_data));

        p_st_thrift_data->i_seq_id = st_compact.i_sqlid;
        memcpy(&p_st_thrift_data->st_l4_trans, p_st_l4_trans, sizeof(L4_transaction));
        p_st_thrift_data->p_report_comm = FRREPORT_BODY_L7LIST_CLONE_COMM(p_st_body_data);
        p_st_thrift_data->p_report_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_body_data);

        //链表添加
        p_st_node = frlist_node_create(p_st_thrift_data);
        frlist_add_tail(&p_st_private->st_thrift_data_list, p_st_node);
    }

    //数据上报
    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
    if(p_st_report_data == NULL)
        goto ERROR;

    if(frreport_data_add_body(p_st_report_data, p_st_body_data) == FR_FAIL)
        goto ERROR;

    p_st_body_data = NULL;

    if(frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
        goto ERROR;

    memset(&p_st_private->st_l4_trans, 0x00, sizeof(L4_transaction));
    p_st_private->ui_data_len = 0;
    bytebuff_free(&p_st_private->p_st_data);

    return APM_L7_ANALYZE_SUCC;

    ERROR:

    memset(&p_st_private->st_l4_trans, 0x00, sizeof(L4_transaction));
    p_st_private->ui_data_len = 0;
    bytebuff_free(&p_st_private->p_st_data);

    if(p_st_report_data)
        frreport_data_free(&p_st_report_data);

    if(p_st_body_data)
        frreport_body_free(&p_st_body_data);

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * \brief   thrift 链表中查找函数 异步对应 seqid
 *
 * \arg     p_st_node       数据节点
 *          p_data          比较数据
 *
 * \return  1 没找到
 *          0 查找到
 *
 */
FR_STATIC int __frthrift_asyc_req_find(Frlist_node *p_st_node, const void *p_data)
{
    thrift_data *p_st_thrift_data = NULL;
    FRTcompact *p_st_compact = (FRTcompact *)p_data;

    if(p_st_node == NULL || p_st_node->data == NULL || p_st_compact == NULL)
        return 1;

    p_st_thrift_data = (thrift_data *)p_st_node->data;

    if(p_st_thrift_data->i_seq_id == p_st_compact->i_sqlid)
        return 0;

    return 1;

}

/*!
 * \brief   thrift tcopact 协议 response解析
 *
 * \arg     p_st_packet         数据包
 *          p_st_private        私有数据
 *          p_st_conn           CT
 *          p_st_hash_report    上报数据链表
 *
 * \return  APM_L7_ANALYZE_FAIL 失败
 *          APM_L7_ANALYZE_SUCC 成功
 *          APM_L7_ANALYZE_TODO 数据包不完整
 *
 */
int thrift_compact_resp_analyze(Apm_packet *p_st_packet, L7session_thrift_private *p_st_private
        , Conntrack *p_st_conn, Frhash_header *p_st_hash_report)
{
    Frbyte_Packet *p_packet = NULL;
    L4_transaction *p_st_l4_trans = &p_st_private->st_l4_trans;
    unsigned long ul_tmp = 0;
    Frreport_body_data *p_st_body_data = NULL;
    Frreport_data *p_st_report_data = NULL;
    FRTcompact st_compact = {0,0,0};
    thrift_data *p_st_thrift_data = NULL;
    Frlist_node *p_st_node = NULL;;

    if(p_st_private->p_st_data == NULL)
    {
        p_st_private->p_st_data = bytebuff_creat();
        if(p_st_private->p_st_data == NULL)
        {
            FRLOG_ERROR_DETAIL("malloc fail");
            return APM_L7_ANALYZE_FAIL;
        }
    }

    p_packet = p_st_private->p_st_data;
    bytebuff_add(p_packet, p_st_packet->p_payload, p_st_packet->ui_payload_len);
    p_st_l4_trans->l_response_bytes += p_st_packet->ui_payload_len;

    //第一个数据包
    if(p_st_private->ui_data_len == 0)
    {
        p_st_l4_trans->st_response_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_response_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;
        bytebuff_get_int(p_packet, 4, &p_st_private->ui_data_len, BYTE_BIG_ENDIAN);
    }

    if(p_st_private->ui_data_len > (unsigned int)bytebuff_remaining(p_packet))
        return APM_L7_ANALYZE_TODO;

    p_st_body_data = frreport_body_new_l7(p_st_conn);
    if(p_st_body_data == NULL)
    {
        FRLOG_ERROR_DETAIL("malloc fail");
        return APM_L7_ANALYZE_FAIL;
    }

    p_st_l4_trans->st_response_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_response_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

    if(frthrift_tcompact_read_response(p_packet, p_st_body_data, &st_compact, (char *)"response.rpc") == FR_FAIL)
        goto ERROR;

    p_st_node = frlist_find(&p_st_private->st_thrift_data_list, &st_compact, __frthrift_asyc_req_find);
    if(p_st_node == NULL)
    {
        memset(&p_st_private->st_l4_trans, 0x00, sizeof(L4_transaction));
        p_st_private->ui_data_len = 0;
        bytebuff_free(&p_st_private->p_st_data);
        frreport_body_free(&p_st_body_data);

        return FR_SUCC;
    }

    frlist_node_apart(&p_st_private->st_thrift_data_list, p_st_node);
    p_st_thrift_data = (thrift_data *)p_st_node->data;
    frfree(p_st_node);

    //comm
    FRREPORT_BODY_L7LIST_SET_COMM(p_st_body_data, &p_st_thrift_data->p_report_comm);

    //把req数据链表添加到resp中
    FRREPORT_BODY_L7LIST_SET_REQ(p_st_body_data, &p_st_thrift_data->p_report_req);

    //server_time_us
    ul_tmp = (unsigned long)frtime_diff(&p_st_thrift_data->st_l4_trans.st_request_time, &p_st_l4_trans->st_response_time_first_byte);
    if(frreport_body_l7_add_ulong(p_st_body_data, APM_REPORT_KEY_RESP_SERVER_TIME_US, ul_tmp) == FR_FAIL)
        goto ERROR;

    if(frreport_body_l7_add_long(p_st_body_data, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_l4_trans->l_response_bytes) == FR_FAIL)
        goto ERROR;

    if(frreport_body_l7_add_timeval(p_st_body_data, APM_REPORT_KEY_RESP_END_TIMESTAMP, &p_st_l4_trans->st_response_time) == FR_FAIL)
        goto ERROR;

    ul_tmp = (unsigned long)frtime_diff(&p_st_l4_trans->st_response_time_first_byte, &p_st_l4_trans->st_response_time);
    if(frreport_body_l7_add_ulong(p_st_body_data, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, ul_tmp) == FR_FAIL)
        goto ERROR;

    //正常
    if(st_compact.u8_type == 2)
    {
        //resp code 上报
        frreport_body_l7_add_long(p_st_body_data, APM_REPORT_KEY_RESP_CODE, 0);
    }

    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
    if(p_st_report_data == NULL)
        goto ERROR;

    if(frreport_data_add_body(p_st_report_data, p_st_body_data) == FR_FAIL)
        goto ERROR;

    p_st_body_data = NULL;

    if(frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
        goto ERROR;

    memset(&p_st_private->st_l4_trans, 0x00, sizeof(L4_transaction));
    p_st_private->ui_data_len = 0;
    bytebuff_free(&p_st_private->p_st_data);
    frfree(p_st_thrift_data);

    return APM_L7_ANALYZE_SUCC;


    ERROR:
    memset(&p_st_private->st_l4_trans, 0x00, sizeof(L4_transaction));
    p_st_private->ui_data_len = 0;
    bytebuff_free(&p_st_private->p_st_data);

    if(p_st_report_data)
        frreport_data_free(&p_st_report_data);

    if(p_st_body_data)
        frreport_body_free(&p_st_body_data);

    if(p_st_thrift_data)
        frfree(p_st_thrift_data);

    return APM_L7_ANALYZE_FAIL;
}

